using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.Service.Mp.Dto;
using Admin.NET.Application.Service.Payment.Dto;
using Admin.NET.Core;
using Admin.NET.Core.Service;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NewLife.Caching;
using SqlSugar;

namespace Admin.NET.Application.Service.Mp;

/// <summary>
/// 微信小程序个人中心页面相关服务
/// </summary>
[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class MpMyService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly UserManager _userManager;

	private readonly SqlSugarRepository<Owner> _rep;

	private readonly SqlSugarRepository<SysUser> _repuser;

	private readonly ICache _cache;

	private readonly SysCacheService _sysCacheService;

	public MpMyService(UserManager userManager, SqlSugarRepository<Owner> rep, ICache cache, SqlSugarRepository<SysUser> repuser, SysCacheService sysCacheService)
	{
		_userManager = userManager;
		_rep = rep;
		_cache = cache;
		_sysCacheService = sysCacheService;
		_repuser = repuser;
	}

	/// <summary>
	/// 修改密码
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/mp/my/changepassword")]
	public async Task ChangePassword(ChangePasswordInput input)
	{
		string enold = MD5Encryption.Encrypt(input.OldPassword);
		Owner has = await _rep.GetFirstAsync((Owner u) => u.Id == _userManager.UserId && u.Password == enold);
		if (has == null)
		{
			throw Oops.Bah("密码错误");
		}
		has.Password = MD5Encryption.Encrypt(input.NewPassword);
		has.UpdateTime = DateTime.Now;
		await _rep.UpdateAsync(has);
	}

	/// <summary>
	/// 重置密码-找回密码
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[AllowAnonymous]
	[HttpPost("/mp/my/resetpassword")]
	public async Task ResetPassword(ResetPasswordInput input)
	{
		string key = "CAPTCHA:" + input.Phone;
		if (!_cache.ContainsKey(key))
		{
			throw Oops.Bah("验证码已失效");
		}
		if (input.yzm != _cache.Get<string>(key))
		{
			throw Oops.Bah("验证码无效");
		}
		Owner has = await _rep.GetFirstAsync((Owner u) => u.PhoneNumber == input.Phone);
		if (has == null)
		{
			throw Oops.Bah("手机号不存在");
		}
		has.Password = MD5Encryption.Encrypt(input.Password);
		has.UpdateTime = DateTime.Now;
		await _rep.UpdateAsync(has);
	}

	/// <summary>
	/// 重置密码-找回密码
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[AllowAnonymous]
	[HttpPost("/mp/my/resetpasswordapp")]
	public async Task ResetPasswordApp(ResetPasswordInput input)
	{
		string key = "CAPTCHA:" + input.Phone;
		if (!_cache.ContainsKey(key))
		{
			throw Oops.Bah("验证码已失效");
		}
		if (input.yzm != _cache.Get<string>(key))
		{
			throw Oops.Bah("验证码无效");
		}
		SysUser has = await _repuser.GetFirstAsync((SysUser u) => u.Phone == input.Phone);
		if (has == null)
		{
			throw Oops.Bah("手机号不存在");
		}
		has.Password = CryptogramUtil.Encrypt(input.Password);
		has.UpdateTime = DateTime.Now;
		string keyErrorPasswordCount = "sys_errorPasswordCount:" + input.Phone;
		_sysCacheService.Set(keyErrorPasswordCount, 1);
		await _repuser.UpdateAsync(has);
	}

	/// <summary>
	/// 修改手机号
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/mp/my/changephone")]
	public async Task ChangePhone(ChangePhoneInput input)
	{
		if (await _rep.GetFirstAsync((Owner u) => u.Id == _userManager.UserId) == null)
		{
			throw Oops.Bah("账号异常");
		}
		string key = "CAPTCHA:" + input.phone;
		if (!_cache.ContainsKey(key))
		{
			throw Oops.Bah("验证码已失效");
		}
		if (_cache.Get<string>(key) != input.yzm)
		{
			throw Oops.Bah("验证码错误");
		}
		(from it in _rep.Context.Updateable<Owner>().SetColumns((Owner it) => it.PhoneNumber == input.phone)
			where it.Id == _userManager.UserId
			select it).ExecuteCommand();
	}

	/// <summary>
	/// 绑定邮箱
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/mp/my/changeemail")]
	public async Task ChangeEmail(ChangeEmailInput input)
	{
		if (await _rep.GetFirstAsync((Owner u) => u.Id == _userManager.UserId) == null)
		{
			throw Oops.Bah("账号异常");
		}
		(from it in _rep.Context.Updateable<Owner>().SetColumns((Owner it) => it.Email == input.email)
			where it.Id == _userManager.UserId
			select it).ExecuteCommand();
	}

	/// <summary>
	/// 记录
	/// </summary>
	/// <param name="page"></param>
	/// <param name="limit"></param>
	/// <param name="query"></param>
	/// <param name="roomId"></param>
	/// <param name="isDrawABill">是否开票</param>
	/// <returns></returns>
	[HttpGet("/mp/my/paymentrecords")]
	public async Task<dynamic> GetPaymentRecord(int page, int limit, string query, long? roomId, int? isDrawABill, DateTime? startTime, DateTime? endTime, PayTypeEnum? payType)
	{
		List<Room> rooms = await (from w in _rep.Context.Queryable<Room>()
			where w.OwnerId == (long?)_userManager.UserId
			select w).ToListAsync();
		ISugarQueryable<PaymentRecord> queryable = from u in _rep.Context.Queryable<PaymentRecord>()
			where u.OwnerId == (long?)_userManager.UserId && u.IsGiveAsAPresent == false && (u.IsPay == 1 || u.IsPay == 3 || u.IsPay == 4) && (int)u.PayType != 5
			select u;
		if (!string.IsNullOrWhiteSpace(query))
		{
			queryable = queryable.Where((PaymentRecord u) => u.PaymentName.Contains(query));
		}
		if (roomId.HasValue)
		{
			queryable = queryable.Where((PaymentRecord u) => u.RoomId == roomId);
		}
		else
		{
			List<long> roomIds = rooms.Select((Room s) => s.Id).ToList();
			queryable = queryable.Where((PaymentRecord u) => roomIds.Contains((long)u.RoomId));
		}
		if (isDrawABill.HasValue)
		{
			queryable = queryable.Where((PaymentRecord u) => (int?)u.IsDrawABill == isDrawABill);
		}
		if (payType.HasValue)
		{
			queryable = queryable.Where((PaymentRecord u) => (int?)u.PayType == (int?)payType);
		}
		if (startTime.HasValue)
		{
			queryable = queryable.Where((PaymentRecord u) => u.CreateTime >= startTime);
		}
		if (endTime.HasValue)
		{
			endTime = endTime?.AddDays(1.0);
			queryable = queryable.Where((PaymentRecord u) => u.CreateTime <= endTime);
		}
		return await (from u in queryable
			orderby u.CreateTime descending
			select new PaymentOutput
			{
				Amount = u.Amount,
				PayType = u.PayType,
				BeforeAmount = u.BeforeAmount,
				BillRecordId = u.BillRecordId,
				Body = u.Body,
				BuyerId = u.BuyerId,
				BuyerPayAmount = u.BuyerPayAmount,
				CreateTime = u.CreateTime,
				CreateUserId = u.CreateUserId,
				CreateUserName = u.CreateUserName,
				Id = u.Id,
				IsDeductBalance = u.IsDeductBalance,
				IsDelete = u.IsDelete,
				IsDrawABill = u.IsDrawABill,
				IsPay = u.IsPay,
				NotifyTime = u.NotifyTime,
				OutTradeNo = u.OutTradeNo,
				PaymentName = u.PaymentName,
				ReceiptAmount = u.ReceiptAmount,
				Remark = u.Remark,
				RoomId = u.RoomId,
				RoomName = from r in SqlFunc.Subqueryable<Room>()
					where (long?)r.Id == u.RoomId
					select r.Name,
				Subject = u.Subject,
				TenantId = u.TenantId,
				TradeNo = u.TradeNo,
				TradeStatus = u.TradeStatus,
				UpdateTime = u.UpdateTime,
				UpdateUserId = u.UpdateUserId,
				Bills = u.Bills,
				IsCustomBill = u.IsCustomBill
			}).ToPagedListAsync(page, limit);
	}

	/// <summary>
	/// 获取总额
	/// </summary>
	/// <param name="roomId"></param>
	/// <returns></returns>
	[HttpGet("/mp/my/paymenttotal")]
	public async Task<dynamic> GetPaymentTotal(long? roomId)
	{
		ISugarQueryable<PaymentRecord> query = from w in _rep.Context.Queryable<PaymentRecord>()
			where w.OwnerId == (long?)_userManager.UserId
			select w;
		if (roomId.HasValue)
		{
			query = query.Where((PaymentRecord w) => w.RoomId == roomId);
		}
		return await query.Select((PaymentRecord w) => w.Amount).CountAsync();
	}

	/// <summary>
	/// 账单图表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/mp/my/paymentcharts")]
	public async Task<dynamic> GetCharts([FromQuery] MpChartsInput input)
	{
		var (_expenddata, begin, end) = GetInput(input);
		var (_incomedata, _, _) = GetInput(input);
		new List<FinanceChartsOutput>();
		new List<FinanceChartsOutput>();
		new List<FinanceChartsOutput>();
		int months = (end.Year - begin.Year) * 12 + end.Month - begin.Month;
		List<DateTime> tmpData = (from s in Enumerable.Range(0, months)
			select begin.AddMonths(s)).ToList();
		ISugarQueryable<SingleColumnEntity<DateTime>> queryableLeft1 = _rep.Context.Reportable(tmpData).ToQueryable<DateTime>();
		ISugarQueryable<SingleColumnEntity<DateTime>> queryableLeft2 = _rep.Context.Reportable(tmpData).ToQueryable<DateTime>();
		ISugarQueryable<PaymentRecord> expendData = _expenddata.Where((PaymentRecord u) => u.IsPay == 1);
		ISugarQueryable<PaymentRecord> incomeData = _incomedata.Where((PaymentRecord u) => u.IsPay == 4 && u.IsDeductBalance == (bool?)true);
		List<FinanceChartsOutput> expendresult = queryableLeft1.LeftJoin(expendData, (SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x2.CreateTime.Value.ToString("yyyy-MM") == x1.ColumnName.ToString("yyyy-MM")).GroupBy((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x1.ColumnName).Select((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => new FinanceChartsOutput
		{
			Total = SqlFunc.AggregateSum(x2.Amount),
			Date = x1.ColumnName.ToString("yyyy-MM")
		})
			.ToList();
		queryableLeft2.LeftJoin(incomeData, (SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x2.CreateTime.Value.ToString("yyyy-MM") == x1.ColumnName.ToString("yyyy-MM")).GroupBy((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => x1.ColumnName).Select((SingleColumnEntity<DateTime> x1, PaymentRecord x2) => new FinanceChartsOutput
		{
			Total = SqlFunc.AggregateSum(x2.Amount),
			Date = x1.ColumnName.ToString("yyyy-MM")
		})
			.ToList();
		List<FinanceChartsOutput> sortexpendResult = expendresult.OrderBy((FinanceChartsOutput o) => o.Date).ToList();
		List<FinanceChartsOutput> sortincomeResult = expendresult.OrderBy((FinanceChartsOutput o) => o.Date).ToList();
		var expend = new
		{
			Date = sortexpendResult.Select((FinanceChartsOutput s) => s.Date).ToList(),
			Total = sortexpendResult.Select((FinanceChartsOutput s) => s.Total).ToList()
		};
		var income = new
		{
			Date = sortincomeResult.Select((FinanceChartsOutput s) => s.Date).ToList(),
			Total = sortincomeResult.Select((FinanceChartsOutput s) => Math.Abs(s.Total)).ToList()
		};
		var remaining = new
		{
			Date = income.Date,
			Total = new List<decimal>()
		};
		for (int i = 0; i < income.Date.Count; i++)
		{
			remaining.Total.Add(expend.Total[i] - income.Total[i]);
		}
		return new { expend, income, remaining };
	}

	private (ISugarQueryable<PaymentRecord>, DateTime, DateTime) GetInput(MpChartsInput input)
	{
		ISugarQueryable<PaymentRecord> data = (from u in _rep.Context.Queryable<PaymentRecord>()
			where u.OwnerId == (long?)_userManager.UserId
			select u).WhereIF(input.RoomId.HasValue, (PaymentRecord u) => u.RoomId == input.RoomId);
		DateTime begin = DateTime.MinValue;
		DateTime end = DateTime.MinValue;
		if (!input.Year.HasValue || !input.Month.HasValue)
		{
			throw Oops.Bah("请选择日期范围");
		}
		end = DateTime.Parse(input.Year + "-" + input.Month).AddMonths(1);
		begin = end.AddMonths(-6);
		data = data.Where((PaymentRecord u) => u.CreateTime >= begin && u.CreateTime < end);
		return (data, begin, end);
	}

	/// <summary>
	/// 业主今年所充值的总额，包括线上线下
	/// </summary>
	/// <returns></returns>
	[HttpGet("/mp/my/paytotal")]
	public async Task<dynamic> GetPayTotal()
	{
		int year = DateTime.Today.Year;
		DateTime currentYear = DateTime.Parse($"{year}-01-01");
		decimal sum = (from w in _rep.Context.Queryable<PaymentRecord>()
			where w.OwnerId == (long?)_userManager.UserId && w.CreateTime >= currentYear && w.IsPay == 1
			select w).Sum((PaymentRecord w) => w.Amount);
		decimal sum2 = (from w in _rep.Context.Queryable<PaymentRecord>()
			where w.OwnerId == (long?)_userManager.UserId && w.CreateTime >= currentYear && w.IsPay == 4 && w.IsDeductBalance == (bool?)true
			select w).Sum((PaymentRecord w) => w.Amount);
		return new
		{
			remaining = Math.Round(sum, 2) + Math.Round(sum2, 2),
			expend = Math.Round(sum, 2),
			income = Math.Abs(Math.Round(sum2, 2))
		};
	}

	/// <summary>
	/// 业主今年所充值的房间统计
	/// </summary>
	/// <returns></returns>
	[HttpGet("/mp/my/paywhere")]
	public async Task<List<PayWhereOutput>> GetPayWhere()
	{
		int year = DateTime.Today.Year;
		DateTime currentYear = DateTime.Parse($"{year}-01-01");
		List<PayWhereOutput> groupData = (from w in _rep.Context.Queryable<PaymentRecord>()
			where w.OwnerId == (long?)_userManager.UserId && w.CreateTime >= currentYear && (w.IsPay == 1 || (w.IsPay == 4 && w.IsDeductBalance == (bool?)true))
			group w by w.RoomId into w
			select new PayWhereOutput
			{
				Name = from w1 in SqlFunc.Subqueryable<Room>()
					where (long?)w1.Id == w.RoomId
					select w1.Name,
				Value = SqlFunc.AggregateSum(w.Amount)
			}).ToList();
		List<string> colors = new List<string> { "#4DCCB3", "#5A77EC", "#4E94EC", "#4FD4EB", "#B5ED21" };
		Random rd = new Random();
		foreach (PayWhereOutput item in groupData)
		{
			int index = rd.Next(0, colors.Count);
			item.Color = colors[index];
		}
		return groupData;
	}

	[HttpGet("/mp/my/getqrcodeurl")]
	public async Task<string> GetQRCodeUrl()
	{
		var tenant = await (from u in _rep.Context.Queryable<SysTenant>()
			where u.Id == _userManager.TenantId
			select new { u.IsQRCodeCustom, u.QRCodeUrl }).FirstAsync();
		if (tenant == null || !tenant.IsQRCodeCustom)
		{
			tenant = await (from u in _rep.Context.Queryable<SysTenant>()
				where u.Id == 1300000000001L
				select new { u.IsQRCodeCustom, u.QRCodeUrl }).FirstAsync();
		}
		return tenant.QRCodeUrl;
	}
}
